//基础Modbus数据模型之上增加Modbus数据协议解析的方法
package modbus

import (
	"errors"
	"time"
)

/*type IModbusProtocol interface {
	analyzeBytes([]byte, DirectionType) error
	analyzeStruct() ([]byte, error)
	ToArray() ([]byte, error)
	FromArray([]byte, DirectionType) error
}*/

type ModbusProtocol struct {
	ModbusModel
	time time.Time
	//IModbusProtocol
	//LenBytes byte
}

func (_this *ModbusProtocol) GetTime() time.Time {
	return _this.time
}

func (_this *ModbusProtocol) AnalyzeBytes(data []byte, direction DirectionType) error {
	//_this.ModbusModel.Direction = direction
	_this.ModbusModel.Addr = data[0]
	_this.ModbusModel.Command = CommandType(data[1])
	_this.time = time.Now()
	switch _this.ModbusModel.Command {
	case ReadCoilStatus:
		return _this.readCoilAnalyze(data[2:])
	case ReadInputStatus:
		return _this.readInputAnalyze(data[2:])
	case ReadHoldingRegisters:
		return _this.readHoldingRegistersAnalyze(data[2:])
	case ReadInputRegisters:
		return _this.readInputRegistersAnalyze(data[2:])
	case ForceSingleCoil:
		return _this.forceSingleCoilAnalyze(data[2:])
	case PresetSingleRegister:
		return _this.presetSingleRegisterAnalyze(data[2:])
	case ForceMultipleCoils:
		return _this.forceMultipleCoilsAnalyze(data[2:])
	case PresetMultipleRegisters:
		return _this.presetMultipleRegistersAnalyze(data[2:])
	default:
		return errors.New("command error")
	}
	//return nil
}

func (_this *ModbusProtocol) AnalyzeStruct() ([]byte, error) {
	buffer := make([]byte, 2)
	buffer[0] = _this.ModbusModel.Addr
	buffer[1] = uint8(_this.ModbusModel.Command)
	_this.time = time.Now()
	var buffer2 []byte
	var err error
	switch _this.ModbusModel.Command {
	case ReadCoilStatus:
		buffer2, err = _this.readCoilCommand()
	case ReadInputStatus:
		buffer2, err = _this.readInputCommand()
	case ReadHoldingRegisters:
		buffer2, err = _this.readHoldingRegistersCommand()
	case ReadInputRegisters:
		buffer2, err = _this.readInputRegistersCommand()
	case ForceSingleCoil:
		buffer2, err = _this.forceSingleCoilCommand()
	case PresetSingleRegister:
		buffer2, err = _this.presetSingleRegisterCommand()
	case ForceMultipleCoils:
		buffer2, err = _this.forceMultipleCoilsCommand()
	case PresetMultipleRegisters:
		buffer2, err = _this.presetMultipleRegistersCommand()
	default:
		return nil, errors.New("命令不支持")
	}
	if buffer2 != nil {
		return append(buffer, buffer2...), err
	} else {
		return nil, err
	}
}

func getBitBufferCountFromRegCount(regCount uint8) uint8 {
	return (regCount-1)/8 + 1
}

//func (_this *ModbusProtocol) setPropertyHas(hasRegNo, hasRegLen, hasBufferLen, hasBody bool) {
//	_this.HasRegNo = hasRegNo
//	_this.HasRegLen = hasRegLen
//	_this.HasBufferLen = hasBufferLen
//	_this.HasBody = hasBody
//}

//Read Coil Status (FC=01)
func (_this *ModbusProtocol) readCoilCommand() ([]byte, error) {
	return _this.readHoldingRegistersCommand()
}

//Read Input Status (FC=02)
func (_this *ModbusProtocol) readInputCommand() ([]byte, error) {
	return _this.readHoldingRegistersCommand()
}

//Read Holding Registers (FC=03)
func (_this *ModbusProtocol) readHoldingRegistersCommand() ([]byte, error) {
	//_this.setPropertyHas(true, true, false, false)
	buffer := make([]byte, 4)
	buffer[0] = byte(_this.RegNo >> 8)
	buffer[1] = byte(_this.RegNo & 0xFF)
	buffer[2] = 0x00
	buffer[3] = _this.RegLength
	return buffer, nil
}

//Read Input Registers (FC=04)
func (_this *ModbusProtocol) readInputRegistersCommand() ([]byte, error) {
	return _this.readHoldingRegistersCommand()
}

//Force Single Coil (FC=05)
func (_this *ModbusProtocol) forceSingleCoilCommand() ([]byte, error) {
	if _this.Body == nil {
		return nil, errors.New("没有要写入的数据")
	} else if len(_this.Body) != 1 {
		return nil, errors.New("能且只能写入一个数据")
	}
	//_this.setPropertyHas(true, false, false, true)
	buffer := make([]byte, 4)
	buffer[0] = byte(_this.RegNo >> 8)
	buffer[1] = byte(_this.RegNo & 0xFF)
	if _this.Body[0] == 0 {
		buffer[2] = 0x00
	} else {
		buffer[2] = 0xFF
	}
	buffer[3] = 0x00
	return buffer, nil
}

//Preset Single Register (FC=06)
func (_this *ModbusProtocol) presetSingleRegisterCommand() ([]byte, error) {
	if _this.Body == nil {
		return nil, errors.New("没有要写入的数据")
	} else if len(_this.Body) != 1 {
		return nil, errors.New("能且只能写入一个数据")
	}
	//_this.setPropertyHas(true, false, false, true)
	buffer := make([]byte, 4)
	buffer[0] = byte(_this.RegNo >> 8)
	buffer[1] = byte(_this.RegNo & 0xFF)
	buffer[2] = byte(_this.Body[0] >> 8)
	buffer[3] = byte(_this.Body[0] & 0xFF)
	return buffer, nil
}

//Force Multiple Coils (FC=15)
func (_this *ModbusProtocol) forceMultipleCoilsCommand() ([]byte, error) {
	if _this.Body == nil {
		return nil, errors.New("没有要写入的数据")
	} else if len(_this.Body) < int(_this.RegLength) {
		return nil, errors.New("数据长度不够")
	}
	//_this.setPropertyHas(true, true, true, true)
	_this.BufferLen = getBitBufferCountFromRegCount(_this.RegLength)
	buffer := make([]byte, 5+_this.BufferLen)
	buffer[0] = byte(_this.RegNo >> 8)
	buffer[1] = byte(_this.RegNo & 0xFF)
	buffer[2] = 0x00
	buffer[3] = _this.RegLength
	buffer[4] = _this.BufferLen
	for i := byte(0); i < _this.RegLength; i++ {
		if _this.Body[i] == 0 {
			buffer[5+i/8] = buffer[5+i/8] | (0x01 << uint(i%8))
		}
	}
	return buffer, nil
}

//Preset Multiple Registers (FC=16)
func (_this *ModbusProtocol) presetMultipleRegistersCommand() ([]byte, error) {
	if _this.Body == nil {
		return nil, errors.New("没有要写入的数据")
	} else if len(_this.Body) < int(_this.RegLength) {
		return nil, errors.New("数据长度不够")
	}
	if _this.RegLength > 127 {
		return nil, errors.New("数据长度不能超过127")
	}
	//_this.setPropertyHas(true, true, true, true)
	_this.BufferLen = _this.RegLength * 2
	buffer := make([]byte, 5+_this.RegLength*2)
	buffer[0] = byte(_this.RegNo >> 8)
	buffer[1] = byte(_this.RegNo & 0xFF)
	buffer[2] = 0x00
	buffer[3] = _this.RegLength
	buffer[4] = _this.BufferLen
	for i := byte(0); i < _this.RegLength; i++ {
		buffer[5+2*i] = byte(_this.Body[i] >> 8)
		buffer[6+2*i] = byte(_this.Body[i] & 0xFF)
	}
	return buffer, nil
}

//Read Coil Status (FC=01)
func (_this *ModbusProtocol) readCoilAnalyze(buffer []byte) error {
	if buffer == nil || len(buffer) < 1 {
		return errors.New("数据长度不够")
	}
	_this.BufferLen = buffer[0]
	if _this.BufferLen > byte(len(buffer)-1) {
		return errors.New("数据长度不够")
	}
	if _this.BufferLen != getBitBufferCountFromRegCount(_this.RegLength) {
		return errors.New("数据长度与读取的要求不匹配")
	}
	//_this.setPropertyHas(false, false, true, true)
	_this.Body = make([]uint16, _this.RegLength)
	for i := byte(0); i < _this.BufferLen; i++ {
		for j := byte(0); j < 8; j++ {
			if i*8+j < _this.RegLength {
				_this.Body[i*8+j] = uint16(buffer[i+1]>>uint(j)) & 0x0001
			}
		}
	}
	return nil
}

//Read Input Status (FC=02)
func (_this *ModbusProtocol) readInputAnalyze(buffer []byte) error {
	return _this.readCoilAnalyze(buffer)
}

//Read Holding Registers (FC=03)
func (_this *ModbusProtocol) readHoldingRegistersAnalyze(buffer []byte) error {
	if buffer == nil || len(buffer) < 1 {
		return errors.New("数据长度不够")
	}
	_this.BufferLen = buffer[0]
	if _this.BufferLen > byte(len(buffer)-1) {
		return errors.New("数据长度不够")
	}
	if _this.BufferLen != _this.RegLength*2 {
		return errors.New("数据长度与读取的要求不匹配")
	}
	//_this.setPropertyHas(false, false, true, true)
	_this.Body = make([]uint16, _this.BufferLen/2)
	for i := byte(1); i < _this.BufferLen; i = i + 2 {
		_this.Body[i/2] = uint16(buffer[i])<<8 | uint16(buffer[i+1])
	}
	return nil
}

//Read Input Registers (FC=04)
func (_this *ModbusProtocol) readInputRegistersAnalyze(buffer []byte) error {
	_this.readHoldingRegistersAnalyze(buffer)
	return nil
}

//Force Single Coil (FC=05)
func (_this *ModbusProtocol) forceSingleCoilAnalyze(buffer []byte) error {
	if buffer == nil || len(buffer) != 4 {
		return errors.New("数据长度不够")
	}
	//_this.setPropertyHas(true, false, false, true)
	_this.RegNo = uint16(buffer[0])<<8 | uint16(buffer[1])
	_this.Body = make([]uint16, 1)
	if buffer[2] == 0x00 && buffer[3] == 0x00 {
		_this.Body[0] = 0
	} else if buffer[2] == 0xff && buffer[3] == 0x00 {
		_this.Body[0] = 1
	} else {
		return errors.New("返回的寄存器值错误")
	}
	return nil
}

//Preset Single Register (FC=06)
func (_this *ModbusProtocol) presetSingleRegisterAnalyze(buffer []byte) error {
	if buffer == nil || len(buffer) != 4 {
		return errors.New("数据长度不够")
	}
	_this.RegNo = uint16(buffer[0])<<8 | uint16(buffer[1])
	_this.Body = make([]uint16, 1)
	//_this.setPropertyHas(true, false, false, true)
	_this.Body[0] = uint16(buffer[2])<<8 | uint16(buffer[3])
	return nil
}

//Force Multiple Coils (FC=15)
func (_this *ModbusProtocol) forceMultipleCoilsAnalyze(buffer []byte) error {
	if buffer == nil || len(buffer) != 4 {
		return errors.New("数据长度不够")
	}
	//_this.setPropertyHas(true, true, false, false)
	_this.RegNo = uint16(buffer[0])<<8 | uint16(buffer[1])
	_this.RegLength = buffer[3]
	return nil
}

//Preset Multiple Registers (FC=16)
func (_this *ModbusProtocol) presetMultipleRegistersAnalyze(buffer []byte) error {
	return _this.forceMultipleCoilsAnalyze(buffer)
}
